<?php

namespace app\controller\Api\V1\Client;

use app\helper\Config;
use app\helper\GetProductInfo;
use app\model\ClientEnroll;
use app\model\ControlCenterVersion;
use app\model\DistrictService;
use app\model\GameEngine;
use app\model\GameVersionRelevance;
use app\model\GuardiansVersion;
use app\model\Server;
use app\model\ToolServer;
use app\request\ClientInit;
use Exception;
use Illuminate\Support\Str;
use support\Request;
use support\Response;

class InitController
{

    protected GetProductInfo $getProductInfoRe;
    protected Config $configRe;


    public function __construct()
    {
        $this->getProductInfoRe = GetProductInfo::getInstance();
        $this->configRe = Config::getInstance();
    }


    /**
     * 初始化
     *
     * @param Request $request
     * @return Response
     * @throws Exception
     */
    public function Init(Request $request): Response
    {

        $validate = new ClientInit;

        if (!$validate->scene('init')->check($request->all())) {
            throw new Exception($validate->getError(), 500);
        }

        if (empty($request->input('release_type'))) {
            if (!empty($request->input('mch_id'))) {
                $productInfo = $this->getProductInfoRe->GetMerchantPlatform();
                $user = $request->input('mch_id');
            } elseif (!empty($request->input('open_id'))) {
                $productInfo = $this->getProductInfoRe->GetDeveloperPlatform();
                $user = $request->input('open_id');
            } else {
                throw new Exception('配置信息填写有误，商户ID和开发者ID不能同时为空', 500);
            }

            $toolServerInfo = ToolServer::query()->where('product', $productInfo['ulid'])
                ->where('organization', $user)->where('ip', $request->input('server_ip'))
                ->where('port', $request->input('server_port'))->where('state', 1)->first();

            if (!$toolServerInfo) {
                throw new Exception('工具服不存在，请前往对应平台配置', 500);
            }

            $toolServerInfo = $toolServerInfo->toArray();

            try {
                $data = [
                    'ulid' => $toolServerInfo['ulid'],
                    'area_name' => $toolServerInfo['title'],
                    'is_test' => 1,
                    'state' => $toolServerInfo['state'],
                    'server_id' => $toolServerInfo['ulid'],
                    'game_engine_id' => '',
                    'lander_group_id' => 1,
                    'list_title' => $toolServerInfo['title'],
                    'server' => [
                        "ulid" => $toolServerInfo['ulid'],
                        "title" => $toolServerInfo['title'],
                        "gate_role_host" => $toolServerInfo['ip'],
                        "gate_role_port" => $toolServerInfo['port'],
                    ]
                ];
            } catch (Exception) {
                throw new Exception('工具服不存在，请前往对应平台配置', 500);
            }
        } else {
            $clientEnrollInfo = ClientEnroll::query()->where('merchant', $request->input('mch_id'))
                ->where('game', $request->input('game_id'))
                ->where('ip', $request->getRealIp())
                ->where('state', 1)->first();

            if (!$clientEnrollInfo) {
                throw new Exception("客户端未授权", 500);
            }
            $clientEnrollInfo = $clientEnrollInfo->toArray();
            if ($clientEnrollInfo['code'] !== $request->input('auth')) {
                throw new Exception('授权验证失败', 500);
            }


            $districtServiceInfo = DistrictService::query()->with(['TestAreaConfig', 'OfficialAreaConfig', 'Server', 'LanderService'])
                ->has('Server')->has('LanderService')
                ->where('merchant', $request->input('mch_id'))
                ->where('game', $request->input('game_id'))
                ->where('server', $clientEnrollInfo['server'])
                ->first();

            if (!$districtServiceInfo) {
                throw new Exception('游戏区服不存在', 500);
            }

//            if ($districtServiceInfo['state'] == 0) {
//                throw new Exception('游戏区服已关闭', 500);
//            }

            $data = [
                'ulid' => $districtServiceInfo['ulid'],
                'area_name' => $districtServiceInfo['is_test'] ? $districtServiceInfo->TestAreaConfig['title'] : $districtServiceInfo->OfficialAreaConfig['title'],
                'is_test' => $districtServiceInfo['is_test'],
                'state' => $districtServiceInfo['state'],
                'server_id' => $districtServiceInfo->Server->ulid,
                'game_engine_id' => $districtServiceInfo['game_engine'],
                'lander_group_id' => $districtServiceInfo->LanderService->parent_ulid,
                'list_title' => $districtServiceInfo->Server->title,
                'server' => $districtServiceInfo->Server->makeHidden([
                    'id',
                    'server_type',
                    'instance_id',
                    'instance_ip',
                    'instance_port',
                    'merchant',
                    'game',
                    'open_at',
                    'expire_at',
                    'state',
                    'remark',
                    'game_area',
                    'created_at',
                    'updated_at',
                    'deleted_at',
                ]),
            ];
        }

        return jsonRe(['info' => $data]);

    }


    /**
     * 初始化 V2
     *
     * @param Request $request
     * @return Response
     * @throws Exception
     */
    public function InitV2(Request $request): Response
    {

        $validate = new ClientInit;

        if (!$validate->scene('init')->check($request->all())) {
            throw new Exception($validate->getError(), 500);
        }

        if (empty($request->input('release_type'))) {
            if (!empty($request->input('mch_id'))) {
                $productInfo = $this->getProductInfoRe->GetMerchantPlatform();
                $user = $request->input('mch_id');
            } elseif (!empty($request->input('open_id'))) {
                $productInfo = $this->getProductInfoRe->GetDeveloperPlatform();
                $user = $request->input('open_id');
            } else {
                throw new Exception('配置信息填写有误，商户ID和开发者ID不能同时为空', 500);
            }

            $toolServerInfo = ToolServer::query()->where('product', $productInfo['ulid'])
                ->where('organization', $user)->where('ip', $request->input('server_ip'))
                ->where('port', $request->input('server_port'))->where('state', 1)->first();

            if (!$toolServerInfo) {
                throw new Exception('工具服不存在，请前往对应平台配置', 500);
            }

            $toolServerInfo = $toolServerInfo->toArray();

            try {
                $data = [
                    'server_id' => $toolServerInfo['ulid'],
                    'server' => [
                        'region_id' => $toolServerInfo['ulid'],
                        'server_name' => $toolServerInfo['title'],
                        'gate_run_host' => $toolServerInfo['ip'],
                        'gate_run_port' => $toolServerInfo['port'],
                        'game_engine' => null,
                        'client_version' => null,
                    ],
                ];
            } catch (Exception) {
                throw new Exception('工具服不存在，请前往对应平台配置', 500);
            }
        } else {
            $clientEnrollInfo = ClientEnroll::query()->where('merchant', $request->input('mch_id'))
                ->where('game', $request->input('game_id'))
                ->where('ip', $request->getRealIp())
                ->where('state', 1)->first();

            if (!$clientEnrollInfo) {
                throw new Exception('客户端未授权', 500);
            }
            $clientEnrollInfo = $clientEnrollInfo->toArray();
            if ($clientEnrollInfo['code'] !== $request->input('auth')) {
                throw new Exception('授权验证失败', 500);
            }


            $districtServiceInfo = DistrictService::query()->with(['TestAreaConfig', 'OfficialAreaConfig', 'Server', 'LanderService'])
                ->where('merchant', $request->input('mch_id'))
                ->where('game', $request->input('game_id'))
                ->where('server', $clientEnrollInfo['server'])
                ->first();

            if (!$districtServiceInfo) {
                throw new Exception('游戏区服不存在', 500);
            }

//            if ($districtServiceInfo['state'] == 0) {
//                throw new Exception('游戏区服已关闭', 500);
//            }

            $data = [
                'server_id' => $districtServiceInfo->Server->ulid,
                'server' => [
                    'region_id' => $districtServiceInfo['ulid'],
                    'server_name' => $districtServiceInfo['is_test'] ? $districtServiceInfo->TestAreaConfig['title'] : $districtServiceInfo->OfficialAreaConfig['title'],
                    'gate_run_host' => $districtServiceInfo->Server->gate_role_host,
                    'gate_run_port' => $districtServiceInfo->Server->gate_role_port,
                    'game_engine' => $districtServiceInfo->Server->game_engine,
                    'client_version' => $districtServiceInfo->Server->client_version,
                ],
            ];
        }

        return jsonRe(['info' => $data]);

    }


    /**
     * RocketMQ初始化
     *
     * @param Request $request
     * @return Response
     * @throws Exception
     */
    public function InitRocketMQ(Request $request): Response
    {

        $validate = new ClientInit;

        if (!$validate->scene('init-rocket-mq')->check($request->all())) {
            throw new Exception($validate->getError(), 500);
        }


        if (empty($request->input('release_type'))) {
            if (!empty($request->input('mch_id'))) {
                $productInfo = $this->getProductInfoRe->GetMerchantPlatform();
                $user = $request->input('mch_id');
            } elseif (!empty($request->input('open_id'))) {
                $productInfo = $this->getProductInfoRe->GetDeveloperPlatform();
                $user = $request->input('open_id');
            } else {
                throw new Exception('配置信息填写有误，商户ID和开发者ID不能同时为空', 500);
            }

            $toolServerInfo = ToolServer::query()->where('product', $productInfo['ulid'])
                ->where('organization', $user)->where('ip', $request->input('server_ip'))
                ->where('port', $request->input('server_port'))->where('state', 1)->first();

            if (!$toolServerInfo) {
                throw new Exception('工具服不存在，请前往对应平台配置', 500);
            }

            $toolServerInfo = $toolServerInfo->toArray();

            try {
                $data = [
                    'mch_id' => $request->input('mch_id'),
                    'game_id' => $request->input('game_id'),
                    'area_id' => $toolServerInfo['ulid'],
                    'area_name' => $toolServerInfo['title'],
                    'server_id' => $toolServerInfo['ulid'],
                    "gate_role_host" => $toolServerInfo['ip'],
                    "gate_role_port" => $toolServerInfo['port'],
                ];
            } catch (Exception) {
                throw new Exception('工具服不存在，请前往对应平台配置', 500);
            }
        } else {
            $serverInfo = Server::query()->where('instance_ip', $request->getRealIp())->first();
            if (!$serverInfo) {
                throw new Exception('客户端未授权', 500);
            }

            $serverInfo = $serverInfo->toArray();

            $data = [
                'mch_id' => $request->input('mch_id'),
                'game_id' => $request->input('game_id'),
                'area_id' => null,
                'area_name' => null,
                'server_id' => $serverInfo['ulid'],
                "gate_role_host" => $serverInfo['gate_role_host'],
                "gate_role_port" => $serverInfo['gate_role_port'],
            ];
        }


        return jsonRe([
            'base' => $data,
            'rocketMQ' => [
                'accessKey' => $this->configRe->Get('aliyun_rocket_mq_access_key_id'),
                'accessSecret' => $this->configRe->Get('aliyun_rocket_mq_access_key_secret'),
                'endpoint' => $this->configRe->Get('aliyun_rocket_mq_endpoint'),
                'instanceId' => $this->configRe->Get('aliyun_rocket_mq_instance_id'),
                'topic' => $this->configRe->Get('aliyun_rocket_mq_topic'),
                'group' => 'GID_' . Str::replace('.', '_', $request->getRealIp()),
                'latencyTime' => 15,
            ]
        ]);

    }


    /**
     * 获取配置信息
     *
     * @return array
     * @throws Exception
     */
    public function GetConfigInfo(): array
    {

        $guardianInfo = GuardiansVersion::query()->where('state', 1)
            ->where('is_stable', 1)->latest('title')
            ->latest('id')->take(1)->first();

        if (!$guardianInfo) {
            throw new Exception('未配置守护者下载信息', 500);
        }
        $guardianInfo = $guardianInfo->toArray();

        $controlCenterInfo = ControlCenterVersion::query()->where('state', 1)
            ->where('is_stable', 1)->latest('title')
            ->latest('id')->take(1)->first();
        if (!$controlCenterInfo) {
            throw new Exception('未配置控制中心下载信息', 500);
        }
        $controlCenterInfo = $controlCenterInfo->toArray();

        // 一般更新稳定版
        $newGameEngineInfo = GameEngine::query()->where('state', 1)
            ->where('is_force', 0)->where('is_stable', 1)
            ->latest('title')->take(1)->first();
        if (!$newGameEngineInfo) {
            throw new Exception('未配置游戏引擎下载信息', 500);
        }
        $newGameEngineInfo = $newGameEngineInfo->toArray();

        // 强制更新稳定版
        $stableGameEngineInfo = GameEngine::query()->where('state', 1)
            ->where('is_stable', 1)->where('is_force', 1)
            ->latest('title')->take(1)->first();
        if (!$stableGameEngineInfo) {
            $stableGameEngineInfo = $newGameEngineInfo;
        } else {
            $stableGameEngineInfo = $stableGameEngineInfo->toArray();
        }

        return [
            'guardian' => $guardianInfo,
            'controlCenter' => $controlCenterInfo,
            'newGameEngine' => $newGameEngineInfo,
            'stableGameEngine' => $stableGameEngineInfo,
        ];

    }


    /**
     * 版本初始化
     *
     * @param Request $request
     * @return Response
     * @throws Exception
     */
    public function InitVersion(Request $request): Response
    {

        $info = $this->GetConfigInfo();

        $data = [
            'guardian' => [
                'version' => $info['guardian']['title'],
                'guardianlink' => $info['guardian']['path'],
            ],
            'gamecenter' => [
                'version' => $info['controlCenter']['title'],
                'gamecenterlink' => $info['controlCenter']['path'],
            ],
            'engine' => [
                'version' => $info['newGameEngine']['title'],
                'enginelink' => $info['newGameEngine']['path'],
                'forc' => $info['newGameEngine']['is_force'] === 1,
            ],
            'stable' => [
                'version' => $info['stableGameEngine']['title'],
                'enginelink' => $info['stableGameEngine']['path'],
            ],
        ];

        return jsonRe($data);

    }


    /**
     * 引擎初始化
     *
     * @param Request $request
     * @return Response
     * @throws Exception
     */
    public function InitEngine(Request $request): Response
    {

        $info = $this->GetConfigInfo();

        $ip = $request->getRealIp();

        $serverInfo = Server::query()->where('instance_ip', $ip)->first();
        if (!$serverInfo) {
            throw new Exception('服务器不存在', 500);
        }
        $serverInfo = $serverInfo->toArray();

        $areaInfo = DistrictService::query()->where('server', $serverInfo['ulid'])->first();
        if (!$areaInfo) {
            throw new Exception('区服不存在', 500);
        }


        $getProductInfo = GetProductInfo::getInstance();
        $merchantPlatform = $getProductInfo->GetMerchantPlatform();
        $gameVersion = GameVersionRelevance::query()->has('VersionBind')->where('product', $merchantPlatform['ulid'])->where('game', $areaInfo['game'])
            ->latest('created_at')->first();

        $portCount = 0;

        $data = [
            'enginecount' => 1,
            'gamecenter' => [
                'version' => $info['controlCenter']['title'],
                'gamecenterlink' => $info['controlCenter']['path'],
            ],
            'local_1' => [
                'version' => $info['newGameEngine']['title'],
                'enginelink' => $info['newGameEngine']['path'],
                'path' => 'C:\\MirServer',
                'game_version' => $gameVersion->VersionBind->url ?? null,  // 七牛云
                'serverid' => $areaInfo->ulid,
                'port' => 7000 + $portCount,
                'chost' => '127.0.0.1',
                'cport' => 4000 + $portCount,
                'update' => false,
            ]
        ];

        return jsonRe($data);

    }


    /**
     * 配置初始化
     *
     * @param Request $request
     * @return Response
     * @throws Exception
     */
    public function InitConfig(Request $request): Response
    {

        $info = $this->GetConfigInfo();

        $serverInfo = Server::query()->has('ServerType')->where('instance_ip', $request->getRealIp())->first();
        if (!$serverInfo) {
            throw new Exception('服务器不存在', 500);
        }
        $serverType = $serverInfo->ServerType;
        $serverInfo = $serverInfo->toArray();

        $areaInfo = DistrictService::query()->where('server', $serverInfo['ulid'])->first();
        if (!$areaInfo) {
            throw new Exception('区服不存在', 500);
        }

        if ($serverType->type === 2) {
            $loginGateThread = $serverType->TencentInstance->login_gate_thread;
            $runGateThread = $serverType->TencentInstance->run_gate_thread;
            $dbServerThread = $serverType->TencentInstance->db_server_thread;
            $m2ServerThread = $serverType->TencentInstance->m2_server_thread;
        } else {
            $loginGateThread = $serverType->AliInstance->login_gate_thread;
            $runGateThread = $serverType->AliInstance->run_gate_thread;
            $dbServerThread = $serverType->AliInstance->db_server_thread;
            $m2ServerThread = $serverType->AliInstance->m2_server_thread;
        }

        $portCount = 0;

        $data = [
            'login' => [
                'port7000' => [
                    'host' => $serverInfo['instance_ip'],
                    'port' => ((int)$serverInfo['gate_login_port'] ?? 7000) + $portCount
                ],
                'port5500' => [
                    'host' => '127.0.0.1',
                    'port' => 5100 + $portCount
                ],
                'workthrnumber' => $loginGateThread ?? 1,
                'checksendlength' => true,
            ],
            'dbserver' => [
                'port5100' => [
                    'host' => '127.0.0.1',
                    'port' => 5100 + $portCount
                ],
                'port6000' => [
                    'host' => '127.0.0.1',
                    'port' => 6000 + $portCount
                ],
                'tread6000count' => $dbServerThread ?? 1,
                'treadcount5100' => $dbServerThread ?? 1,
                'area_id' => $serverInfo['game_area'] ?? 0,
            ],
            'm2server' => [
                'port5000' => [
                    'host' => '127.0.0.1',
                    'port' => 5000 + $portCount
                ],
                'port6000' => [
                    'host' => '127.0.0.1',
                    'port' => 6000 + $portCount
                ],
                'tread6000number' => $m2ServerThread ?? 1,
                'workthrnumber' => $m2ServerThread ?? 1,
            ],
            'rungate' => [
                'port5000' => [
                    'host' => '127.0.0.1',
                    'port' => 5000 + $portCount
                ],
                'port7200' => [
                    'host' => $serverInfo['gate_game_host'] ?? $serverInfo['instance_ip'],
                    'port' => ((int)$serverInfo['gate_game_port'] ?? 7200) + $portCount
                ],
                'workthrnumber' => $runGateThread ?? 1,
                "rgsacceptmaxrequest" => 2048,
                "rgsacceptminrequest" => 256,
                "rgsmaxsendingqueuesize" => 32,
                "rgsworkercount" => 8,
                "rgsmaxworkercount" => 10,
                "rgsmaxtaskworker" => 10
            ],
            'server' => [
                'contelcenter' => [
                    'dbserver' => 0,
                    'm2server' => 0,
                    'rungate' => 0,
                    'logingate' => 0,
                ],
                'serverconfig' => [
                    'workfolder' => 'C:\\MirServer',
                    'servername' => $serverInfo['title'],
                    'serverid' => $areaInfo->ulid,
                    'timeout' => 5,
                    'state' => 0, // 初始化
                ],
                'agent' => [
                    'open_id' => 0,
                    'mch_id' => $serverInfo['merchant'],
                    'game_id' => $serverInfo['game'] ?? 0,
                    'mchtype' => 1,
                    'release_type' => 1,
                    'regoem' => 0,
                ],
                'database' => [
                    'dbprovider' => 0,
                    'host' => $serverInfo['sql_host'],
                    'port' => $this->configRe->Get('system_test') ? 1433 : 38187,
                    'databasename' => aesCrypt($serverInfo['sql_name']),
                    'userid' => aesCrypt($serverInfo['sql_user']),
                    'pwd' => aesCrypt($serverInfo['sql_password']),
                ],
//                'redis' => [
////                    'host' => $serverInfo['instance_ip'],
//                    'host' => '127.0.0.1',
//                    'port' => 6379,
////                    'pwd' => $serverInfo['redis_password'],
//                    'pwd' => 'yE7E42KRLQg9*usgwt2z',  // 暂时先用固定值
//                ],
            ],
            "center" => [
                "port4000" => [
                    "host" => '127.0.0.1',
                    "port" => 4000 + $portCount
                ],
            ],
            'version' => [
                'guardian' => [
                    'version' => $info['guardian']['title'],
                    'guardianlink' => $info['guardian']['path'],
                ],
            ],
        ];

        return jsonRe($data);

    }

}